#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "rngs.h"

#define NOISY_TEST 1

void checkScoreFor_initial(struct gameState *post) {
  int test = scoreFor(0, post);
  assert(test == 3);
}

void checkScoreFor_one_card(struct gameState *pre, int card, int score) {
  struct gameState post;
  int test;
  int deckIndex;
  int i = 0;
  memcpy (&post, pre, sizeof(struct gameState));
  // test card in hand
  while(post.hand[0][i] == estate) {
      i++;
  }
  post.hand[0][i] = card;
  deckIndex = post.deckCount[0];
  post.deck[0][deckIndex] = copper;
  post.deckCount[0]++;
  test = scoreFor(0, &post);
  assert(test == score);
  endTurn(&post);
  // test card in deck
  deckIndex = post.deckCount[1];
  post.deck[1][deckIndex] = card;
  post.deckCount[1]++;
  test = scoreFor(1, &post);
  assert(test == score);
  endTurn(&post);
  // test card in discard
  post.discard[2][0] = card;
  post.discardCount[2]++;
  test = scoreFor(2, &post);
  assert(test == score);
}

void checkScoreFor_three_cards(struct gameState *pre, int card1, int card2, int card3, int score) {
  struct gameState post;
  int test;
  int index;
  int cardSwap;
  memcpy (&post, pre, sizeof(struct gameState));
  // test one of each in each card location
  // hand
  cardSwap = post.hand[0][0];
  post.hand[0][0] = card1;
  index = post.deckCount[0];
  post.deck[0][index] = cardSwap;
  post.deckCount[0]++;
  index++;
  // deck
  post.deck[0][index] = card2;
  post.deckCount[0]++;
  // discard
  index = post.discardCount[0];
  post.discard[0][index] = card3;
  post.discardCount[0]++;
  test = scoreFor(0, &post);
  assert(test == score);
  // test one of each in hand
  // hand
  endTurn(&post);
  cardSwap = post.hand[1][0];
  post.hand[1][0] = card1;
  index = post.deckCount[1];
  post.deck[1][index] = cardSwap;
  post.deckCount[1]++;
  index++;
  cardSwap = post.hand[1][1];
  post.hand[1][1] = card2;
  post.deck[1][index] = cardSwap;
  post.deckCount[1]++;
  index++;
  cardSwap = post.hand[1][2];
  post.hand[1][2] = card3;
  post.deck[1][index] = cardSwap;
  post.deckCount[1]++;
  test = scoreFor(1, &post);
  assert(test == score);
  // test one of each in deck
  // hand
  endTurn(&post);
  index = post.deckCount[2];
  post.deck[2][index] = card1;
  post.deckCount[2]++;
  index++;
  post.deck[2][index] = card2;
  post.deckCount[2]++;
  index++;
  post.deck[2][index] = card3;
  post.deckCount[2]++;
  test = scoreFor(2, &post);
  assert(test == score);
  // test one of each in discard
  // hand
  endTurn(&post);
  index = post.discardCount[3];
  post.discard[3][index] = card1;
  post.discardCount[3]++;
  index++;
  post.discard[3][index] = card2;
  post.discardCount[3]++;
  index++;
  post.discard[3][index] = card3;
  post.discardCount[3]++;
  test = scoreFor(3, &post);
  assert(test == score);
}
void checkScoreFor_gardens(struct gameState *pre, int count, int score) {
  struct gameState post;
  int index;
  int i;
  int test;
  memcpy (&post, pre, sizeof(struct gameState));
  index = post.deckCount[0];
  for (i=0; i<count; i++) {
    post.deck[0][index] = gardens;
    post.deckCount[0]++;
    index++;
  }
  test = scoreFor(0, &post);
  assert(test == score);
}

int run_tests6() {
  int k[10] = {adventurer, council_room, feast, gardens, mine,
	       remodel, smithy, village, baron, great_hall};
  struct gameState G;
  initializeGame(4, k, 1, &G);
  printf ("FIXED TESTING scoreFor.\n");
  printf ("Testing scoreFor: initial deck.\n");
  checkScoreFor_initial(&G);
  printf ("Testing scoreFor: one extra curse in deck.\n");
  checkScoreFor_one_card(&G, curse, 2);
  printf ("Testing scoreFor: one extra estate in deck.\n");
  checkScoreFor_one_card(&G, estate, 4);
  printf ("Testing scoreFor: one extra duchy in deck.\n");
  checkScoreFor_one_card(&G, duchy, 6);
  printf ("Testing scoreFor: one extra province in deck.\n");
  checkScoreFor_one_card(&G, province, 9);
  printf ("Testing scoreFor: one extra great hall in deck.\n");
  checkScoreFor_one_card(&G, great_hall, 4);
  printf ("Testing scoreFor: one extra gardens in deck.\n");
  checkScoreFor_one_card(&G, gardens, 4);

  printf ("Testing scoreFor: three extra curses.\n");
  checkScoreFor_three_cards(&G, curse, curse, curse, 0);
  printf ("Testing scoreFor: three extra estates.\n");
  checkScoreFor_three_cards(&G, estate, estate, estate, 6);
  printf ("Testing scoreFor: three extra duchys.\n");
  checkScoreFor_three_cards(&G, duchy, duchy, duchy, 12);
  printf ("Testing scoreFor: three extra provinces.\n");
  checkScoreFor_three_cards(&G, province, province, province, 21);
  printf ("Testing scoreFor: three extra great halls.\n");
  checkScoreFor_three_cards(&G, great_hall, great_hall, great_hall, 6);
  printf ("Testing scoreFor: three extra gardens.\n");
  checkScoreFor_three_cards(&G, gardens, gardens, gardens, 6);

  printf ("Testing scoreFor: curse, estate, duchy.\n");
  checkScoreFor_three_cards(&G, curse, estate, duchy, 6);
  printf ("Testing scoreFor: estate, duchy, province.\n");
  checkScoreFor_three_cards(&G, estate, duchy, province, 13);
  printf ("Testing scoreFor: duchy, province, great_hall.\n");
  checkScoreFor_three_cards(&G, duchy, province, great_hall, 13);
  printf ("Testing scoreFor: province, great_hall, gardens.\n");
  checkScoreFor_three_cards(&G, province, great_hall, gardens, 11);
  printf ("Testing scoreFor: great_hall, gardens, estate.\n");
  checkScoreFor_three_cards(&G, great_hall, gardens, estate, 6);
  printf ("Testing scoreFor: gardens, estate, curse.\n");
  checkScoreFor_three_cards(&G, gardens, estate, curse, 4);
  printf ("Testing scoreFor: estate, province, gardens.\n");
  checkScoreFor_three_cards(&G, estate, province, gardens, 11);
  printf ("Testing scoreFor: curse, duchy, great_hall.\n");
  checkScoreFor_three_cards(&G, curse, duchy, great_hall, 6);

  printf ("Testing scoreFor: 5 gardens.\n");
  checkScoreFor_gardens(&G, 5, 8);
  printf ("Testing scoreFor: 10 gardens.\n");
  checkScoreFor_gardens(&G, 10, 23);
  printf ("Testing scoreFor: 20 gardens.\n");
  checkScoreFor_gardens(&G, 20, 63);

  printf ("ALL TESTS OK\n");
  return 0;
}
